package service

import (
	"bytes"
	"encoding/json"
	"fmt"
	"github.com/bgmp/config"
	"github.com/bgmp/model"
	log "github.com/sirupsen/logrus"
	"io/ioutil"
	"net/http"
	"strconv"
	"strings"
	"time"
)

const MG_L_TO_MMOL_L = 18.1818

func BgPredict(bgs []model.Bg) []PredictResult {
	length := 0

	var str string
	var temp_str string
	for i, j := 0, len(bgs)-1; i < j; i, j = i+1, j-1 {
		bgs[i], bgs[j] = bgs[j], bgs[i] //reverse the slice
	}
	for _, v := range bgs {
		length += 1
		temp_str = fmt.Sprintf("[\"%s\",%f],", v.Time.Format("2006-01-02 15:04:05"), v.Value*MG_L_TO_MMOL_L)
		str += temp_str
	}
	if length < 96 {
		length = 96 - length
		for i := 0; i < length; i++ {
			str += temp_str
		}
	}
	str = str[:len(str)-1]
	str = fmt.Sprintf("{\"seq\":[%s]}", str)
	//fmt.Println(str)

	url := config.GetAlgorithmUrl()
	payload := []byte(str)

	resp, err := http.Post(url, "text/plain", bytes.NewBuffer(payload))
	if err != nil {
		log.Error("Error:", err)
		return nil
	}
	defer resp.Body.Close()

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		log.Error("Error reading response body:", err)
		return nil
	}

	log.Info("Response Status:", resp.Status)
	str = string(body)
	//fmt.Println(str)
	str = str[12 : len(str)-2]
	dataArray := strings.Split(str, `],[`)
	dataArray[0] = dataArray[0][1:len(dataArray[0])]
	dataArray[len(dataArray)-1] = dataArray[len(dataArray)-1][0 : len(dataArray[len(dataArray)-1])-1]
	result := make([]PredictResult, len(dataArray))
	for i, v := range dataArray {
		arr := strings.Split(v, `,`)
		temp := arr[0][1 : len(arr[0])-1]
		stamp, _ := time.ParseInLocation("2006-01-02 15:04:05", temp, time.Local)
		result[i].Time = stamp.Unix()

		if f, err := strconv.ParseFloat(arr[1], 64); err != nil {
			log.Error("Error:", err)
			return nil
		} else {
			result[i].Value = f
		}
	}
	return result
}

type PredictResult struct {
	Time  int64   `json:"time"`
	Value float64 `json:"value"`
}

func Prescription(bgs []model.Bg, extra *AgentExtra, therapy *model.InsulinTherapy) (*PrescriptionResult, error) {
	length := 0

	// 补充到96个并整理合适
	var str string
	var temp_str string
	for i, j := 0, len(bgs)-1; i < j; i, j = i+1, j-1 {
		bgs[i], bgs[j] = bgs[j], bgs[i] //reverse the slice
	}
	for _, v := range bgs {
		length += 1
		temp_str = fmt.Sprintf("[\"%s\",%f],", v.Time.Format("2006-01-02 15:04:05"), v.Value*MG_L_TO_MMOL_L)
		str += temp_str
	}
	if length < 96 {
		length = 96 - length
		for i := 0; i < length; i++ {
			str += temp_str
		}
	}
	str = str[:len(str)-1]
	//str = fmt.Sprintf("{\"seq\":[%s]}", str)

	extraBytes, err := json.Marshal(extra)
	if err != nil {
		return nil, err
	}
	extraStr := string(extraBytes)

	therapyStr, err := json.Marshal(therapy)
	if err != nil {
		return nil, err
	}
	str = fmt.Sprintf("{\"seq\":[%s], \"extra\":%s, \"therapy\":%s}", str, extraStr, therapyStr)
	//log.Info(str)

	url := config.GetPrescriptionUrl()
	payload := []byte(str)

	//log.Info(str)

	resp, err := http.Post(url, "text/plain", bytes.NewBuffer(payload))
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}

	var preRes PrescriptionResult
	err = json.Unmarshal(body, &preRes)
	if err != nil {
		return nil, err
	}

	return &preRes, nil
}

type PrescriptionResult struct {
	Prescription string `json:"prescription"`
}

func Agent(bgs []model.Bg, extra *AgentExtra) ([][]string, error) {
	length := 0

	// 补充到96个并整理合适
	var str string
	var temp_str string
	for i, j := 0, len(bgs)-1; i < j; i, j = i+1, j-1 {
		bgs[i], bgs[j] = bgs[j], bgs[i] //reverse the slice
	}
	for _, v := range bgs {
		length += 1
		temp_str = fmt.Sprintf("[\"%s\",%f],", v.Time.Format("2006-01-02 15:04:05"), v.Value*MG_L_TO_MMOL_L)
		str += temp_str
	}
	if length < 96 {
		temp_str = fmt.Sprintf("[\"%s\",%f],", bgs[0].Time.Format("2006-01-02 15:04:05"), bgs[0].Value*MG_L_TO_MMOL_L)
		length = 96 - length
		for i := 0; i < length; i++ {
			str += temp_str
		}
	}

	seq := str[:len(str)-1]

	extraBytes, err := json.Marshal(extra)
	if err != nil {
		return nil, err
	}
	extraStr := string(extraBytes)

	str = fmt.Sprintf("{\"seq\":[%s], \"extra\":%s}", seq, extraStr)

	payload := []byte(str)

	url := config.GetAgentUrl()

	resp, err := http.Post(url, "text/plain", bytes.NewBuffer(payload))
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}

	var preRes AgentResult
	err = json.Unmarshal(body, &preRes)
	fmt.Println(preRes)
	if err != nil {
		return nil, err
	}
	if preRes.Agent[0][0] == "无需辅助药物" {
		return nil, nil
	}

	return preRes.Agent, nil
}

type AgentExtra struct {
	Gender       int     `json:"gender"`
	Age          int     `json:"age"`
	Bmi          float64 `json:"bmi"`
	Smoke        float64 `json:"smoke"`
	Alcohol      int     `json:"alcohol"`
	Diabetes     float64 `json:"diabetes"`
	Macro        int     `json:"macro"`
	Micro        int     `json:"micro"`
	Hba1c        float64 `json:"hba1c"`
	Hypoglycemia int     `json:"hypoglycemia"`
}

type AgentResult struct {
	Agent [][]string `json:"agent"`
}

func Csii(bgs []model.Bg, extra *AgentExtra, weight float32) (*CsiiResult, error) {
	//length := 0

	// 补充到96个并整理合适
	//var str string
	//var temp_str string
	//for i, j := 0, len(bgs)-1; i < j; i, j = i+1, j-1 {
	//	bgs[i], bgs[j] = bgs[j], bgs[i] //reverse the slice
	//}
	//for _, v := range bgs {
	//	length += 1
	//	temp_str = fmt.Sprintf("[\"%s\",%f],", v.Time.Format("2006-01-02 15:04:05"), v.Value*MG_L_TO_MMOL_L)
	//	str += temp_str
	//}
	//if length <= 0 {
	//	return nil, errors.New("No Data Found!")
	//} else if length < 96 {
	//	temp_str = fmt.Sprintf("[\"%s\",%f],", bgs[0].Time.Format("2006-01-02 15:04:05"), bgs[0].Value*MG_L_TO_MMOL_L)
	//	length = 96 - length
	//	for i := 0; i < length; i++ {
	//		str += temp_str
	//	}
	//}

	//seq := str[:len(str)-1]

	extraBytes, err := json.Marshal(extra)
	if err != nil {
		return nil, err
	}
	extraStr := string(extraBytes)

	//str = fmt.Sprintf("{\"seq\":[%s], \"extra\":%s}", seq, extraStr)
	str := fmt.Sprintf("{\"extra\":%s,\"weight\":%f}", extraStr, weight)

	payload := []byte(str)

	url := config.GetCsiiUrl()

	resp, err := http.Post(url, "text/plain", bytes.NewBuffer(payload))
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}

	//fmt.Println(string(body))
	var preRes CsiiResult
	err = json.Unmarshal(body, &preRes)
	//fmt.Println(preRes)
	if err != nil {
		return nil, err
	}

	return &preRes, nil
}

type CsiiResult struct {
	Basal float32 `json:"basal,omitempty"`
	Bolus float32 `json:"bolus"`
}
